import json
from typing import Optional, Any
import redis.asyncio as redis
from datetime import timedelta

from app.core.config import settings


class RedisClient:
    def __init__(self):
        self.redis = None
    
    async def init_redis_pool(self):
        """Initialize Redis connection pool"""
        self.redis = redis.from_url(
            settings.REDIS_URL, 
            encoding="utf-8", 
            decode_responses=True
        )
        
    async def close_redis_pool(self):
        """Close Redis connection pool"""
        if self.redis:
            await self.redis.close()
    
    async def get(self, key: str) -> Optional[str]:
        """Get value from Redis"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.get(key)
    
    async def set(
        self, 
        key: str, 
        value: str, 
        expire: Optional[int] = None
    ) -> bool:
        """Set value in Redis with optional expiration"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.set(key, value, ex=expire)
    
    async def delete(self, key: str) -> int:
        """Delete key from Redis"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.delete(key)
    
    async def exists(self, key: str) -> int:
        """Check if key exists in Redis"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.exists(key)
    
    async def sadd(self, key: str, *values: str) -> int:
        """Add values to set"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.sadd(key, *values)
    
    async def sismember(self, key: str, value: str) -> bool:
        """Check if value is in set"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.sismember(key, value)
    
    async def hset(self, key: str, mapping: dict) -> int:
        """Set hash field values"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.hset(key, mapping=mapping)
    
    async def hget(self, key: str, field: str) -> Optional[str]:
        """Get hash field value"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.hget(key, field)
    
    async def hgetall(self, key: str) -> dict:
        """Get all hash field values"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.hgetall(key)
    
    async def hdel(self, key: str, *fields: str) -> int:
        """Delete hash fields"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.hdel(key, *fields)
    
    async def expire(self, key: str, seconds: int) -> bool:
        """Set key expiration"""
        if not self.redis:
            await self.init_redis_pool()
        return await self.redis.expire(key, seconds)
    
    # Token management methods
    async def add_to_blacklist(self, jti: str, expire_seconds: int) -> bool:
        """Add token JTI to blacklist"""
        return await self.set(f"blacklist:{jti}", "1", expire_seconds)
    
    async def is_token_blacklisted(self, jti: str) -> bool:
        """Check if token JTI is blacklisted"""
        return await self.exists(f"blacklist:{jti}") > 0
    
    async def store_user_session(
        self, 
        user_id: str, 
        session_data: dict,
        expire_seconds: int = None
    ) -> bool:
        """Store user session data"""
        key = f"session:{user_id}"
        result = await self.hset(key, session_data)
        if expire_seconds:
            await self.expire(key, expire_seconds)
        return result > 0
    
    async def get_user_session(self, user_id: str) -> dict:
        """Get user session data"""
        return await self.hgetall(f"session:{user_id}")
    
    async def delete_user_session(self, user_id: str) -> int:
        """Delete user session"""
        return await self.delete(f"session:{user_id}")


# Global Redis client instance
redis_client = RedisClient()